package path

import (
	"bytes"
	"common/encryp/sm4"
	"crypto/md5"
	"crypto/rand"
	"encoding/base64"
	"errors"
	"strings"
)

const EstoreKeyLen = 16

type EstoreKey [EstoreKeyLen]byte

type PathCoder struct {
}

func trimPath(rawPath string) string {
	p := strings.Trim(rawPath, " ")
	p = strings.Trim(p, "/")
	return p
}

func GetDerivedKey(baseKey []byte, rawPath string) []byte {
	rawPath = trimPath(rawPath)

	var derivedKey = baseKey
	parts := strings.Split(rawPath, "/")
	for _, part := range parts {
		hash := md5.New()
		hash.Write(derivedKey)
		hash.Write([]byte(part))
		derivedKey = hash.Sum(nil)
	}
	return derivedKey
}

//加密 ContentKey
func GetContentKey(derivedKey []byte) ([]byte, []byte, error) {
	var contentKey EstoreKey
	_, err := rand.Read(contentKey[:])
	if err != nil {
		return nil, nil, err
	}
	sm4 := sm4.NewSm4()

	encryptedKey, err := sm4.Encode(contentKey[:], derivedKey)
	if err != nil {
		return nil, nil, err
	}
	if len(encryptedKey) == 0 {
		return nil, nil, errors.New("error encryptedKey len ")
	}
	return contentKey[:], encryptedKey, nil
}

func EncPath(p string, sm4key []byte) ([]byte, string, error) {
	p = trimPath(p)
	sm4 := sm4.NewSm4()
	parts := strings.Split(p, "/")
	var pb pathBuilder
	for _, part := range parts {
		if len(part) == 0 {
			continue
		}
		encPart, err := sm4.Encode([]byte(part), sm4key)
		if err != nil {
			return nil, "", err
		}
		encPartBase64 := base64.URLEncoding.EncodeToString(encPart)
		pb.append(encPartBase64)
	}
	return []byte(pb.String()), p, nil
}

//// 解码路径
func DecPath(p []byte, sm4key []byte) (string, error) {

	parts := bytes.Split(p, []byte("/"))
	//parts := strings.Split(p, "/")
	var pb pathBuilder
	sm4 := sm4.NewSm4()
	for _, part := range parts {
		if len(part) == 0 {
			continue
		}
		part2, err := base64.URLEncoding.DecodeString(string(part))
		if err != nil {
			return "", errors.New("base64 dec error")
		}
		encPart, err := sm4.Decode(part2, sm4key)
		if err != nil {
			return "", err
		}
		pb.append(string(encPart))
	}
	return pb.String(), nil
}

//解码 ContentKey
func ParseContentKey(encryptedKey, derivedKey []byte) ([]byte, error) {
	sm4 := sm4.NewSm4()
	contentKey, err := sm4.Decode(encryptedKey, derivedKey)
	if err != nil {
		return nil, err
	}
	return contentKey, nil
}
